package kik.client;

import java.util.ArrayList;

import kik.client.common.Change;

import com.calclab.emite.core.client.xmpp.session.Session;
import com.calclab.emite.core.client.xmpp.stanzas.Presence;
import com.calclab.suco.client.events.Listener;

/**
 * W klasie ConferenceManager zaimplementowane jest zarządzanie połączeniami w
 * systemie, oraz sterowanie wysyłaniem i odbieraniem wiadomości między
 * klientami komunikatora.
 * 
 * @author Bartłomiej Kucharczyk
 * @author Paweł Kieliszczyk
 * 
 */
public class ConferenceManager {
	/**
	 * Połączenie z serwerem xmpp.
	 * 
	 * @see Connection
	 */
	private Connection connection = new Connection("localhost", this);

	/**
	 * Kolejny numer identyfikacyjny konferencji. Niezbędny do rozróżniania
	 * konferencji rozpoczętych przez danego użytkownika. Każda konferencja
	 * otrzymuje ID postaci login_confNextID.
	 */
	private int confNextID = 0;

	/**
	 * Referencja do panelu konferencji. Jest potrzebna podczas tworzenia nowych
	 * konferencji.
	 */
	private ConferencePanelUI confPanel;

	/**
	 * Referencja do listy kontaktów.
	 */
	private ContactList contactList;

	public ConferenceManager() {
	}

	/**
	 * Łączy się z serwerem xmpp server jako podany użytkownik login.
	 * 
	 * @param login
	 *            Nazwa użytkownika.
	 * @param pass
	 *            Hasło użytkownika.
	 */
	public void connect(String login, String pass) {
		connection.jabberConnect(login, pass);
	}

	/**
	 * @depreciated
	 * @param data
	 * @return
	 * @see #encryptData(String)
	 */
	public String decryptData(String data) {
		return data;
	}

	/**
	 * Rozłączenie z serwerem xmpp.
	 */
	public void disconnect() {
		connection.jabberDisconnect();
	}

	/**
	 * Nie wykorzystywany. Zgodnie z informacjami zawartymi na <a href="http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/cc66751832ec419f"
	 * > tej stronie</a> tworzenie szyfrowania w GWT jest nieoptymalne i
	 * niekoniecznie bezpieczne. Należy zamiast tego wykorzystywać połączenie
	 * SSL, które jest wystarczające.
	 * 
	 * @depreciated
	 * @param data
	 * @return
	 */
	public String encryptData(String data) {
		return data;
	}

	/**
	 * Zwraca panel z konferencjami.
	 * 
	 * @return Panel z konferencjami.
	 */
	public ConferencePanelUI getConferencePanelUI() {
		return confPanel;
	}

	/**
	 * Zwraca login aktualnie połączonego użytkownika.
	 * 
	 * @return Login połączonego użytkownika.
	 * @see Connection#getLogin()
	 */
	public String getLogin() {
		return connection.getLogin();
	}

	/**
	 * Sprawdzenie, czy użytkownik jest zalogowany do serwera xmpp.
	 * 
	 * @return true, jeżeli zalogowany; false w przeciwnym razie.
	 */
	public boolean isLogged() {
		return connection.isLogged();
	}

	/**
	 * Tworzy nową konferencję.
	 * 
	 * @return Referencja do nowo utworzonej konferencji.
	 * @see Conference
	 */
	public Conference newConference() {
		Conference c = new Conference(getLogin() + "_"
				+ Integer.toString(confNextID), this);
		confNextID++;

		onChange(c); // dodanie do listy słuchaczy zmian

		return c;
	}

	/**
	 * Dodanie obserwatora zmian konferencji.
	 * 
	 * @param listener
	 *            Obserwator do dodania.
	 * @see Connection#onChange(Listener)
	 */
	public void onChange(Listener<Change> listener) {
		connection.onChange(listener);
	}

	/**
	 * Usunięcie obserwatora zmian konferencji.
	 * 
	 * @param listener
	 *            Obserwator do usunięcia.
	 * @see Connection#onChangeRemove(Listener)
	 */
	public void onChangeRemove(Listener<Change> listener) {
		connection.onChangeRemove(listener);
	}

	/**
	 * Dodanie obserwatora zmian statusów kontaktów (znajomych).
	 * 
	 * @param listener
	 *            Obserwator do dodania.
	 * @see Connection#onContactChange(Listener)
	 */
	public void onContactChange(Listener<Presence> listener) {
		connection.onContactChange(listener);
	}

	/**
	 * Usunięcie obserwatora zmian statusów kontaktów (znajomych).
	 * 
	 * @param listener
	 *            Obserwator do usunięcia.
	 * @see Connection#onContactChangeRemove(Listener)
	 */
	public void onContactChangeRemove(Listener<Presence> listener) {
		connection.onContactChangeRemove(listener);
	}

	/**
	 * Dodanie obserwatora zmian stanu zalogowania do serwera.
	 * 
	 * @param listener
	 *            Obserwator do dodania.
	 * @see Connection#onLoginChange(Listener)
	 */
	public void onLoginChange(Listener<Session.State> listener) {
		connection.onLoginChange(listener);
	}

	/**
	 * Usunięcie obserwatora zmian stanu zalogowania do serwera.
	 * 
	 * @param listener
	 *            Obserwator do usunięcia.
	 * @see Connection#onLoginChangeRemove(Listener)
	 */
	public void onLoginChangeRemove(Listener<Session.State> listener) {
		connection.onLoginChangeRemove(listener);
	}

	/**
	 * Wysyłanie obiektu zmian do listy użytkowników.
	 * 
	 * @param contacts
	 *            Lista użytkowników, do których wysyłamy.
	 * @param data
	 *            Obiekt zmian, który należy przesłać.
	 */
	public void sendTo(ArrayList<String> contacts, Change data) {
		String serialized = data.serialize();
		
		for (String c : contacts) {
			connection.sendMsg(c, serialized);
		}
	}

	/**
	 * Wysłanie obiektu zmian data do użytkownika user.
	 * 
	 * @param user
	 *            Nazwa użytkownika, do którego należy wysłać wiadomość.
	 * @param data
	 *            Obiekt zmian, który należy przesłać.
	 * @see Change
	 */
	public void sendTo(String user, Change data) {
		connection.sendMsg(user, data.serialize());
	}

	/**
	 * Ustawianie panelu konferencji.
	 * 
	 * @param _confPanel
	 *            Panel z konferencjami do ustawienia.
	 */
	public void setConferencePanelUI(ConferencePanelUI _confPanel) {
		confPanel = _confPanel;
	}

	/**
	 * Ustawienie listy kontaktów
	 * 
	 * @param _contactList
	 *            Referencja do listy kontaktów
	 */
	public void setContactList(ContactList _contactList) {
		contactList = _contactList;
	}

	/**
	 * Przekazuje listę kontaktów użytkownika do instancji klasy ContactList.
	 * 
	 * @param rost
	 *            Tablica zawierająca kontakty użytkownika
	 */
	public void setRoster(ArrayList<String> rost) {
		contactList.setRoster(rost);
	}

	/**
	 * Opuszczenie konferencji conf. Wysyłane są powiadomienia do wszystkich
	 * użytkowników, o opuszczeniu konferencji, a następnie konferencja jest
	 * usuwana z panelu konferencji.
	 * 
	 * @param conf
	 *            Konferencja, którą opuszczamy.
	 */
	public void exitConference(Conference conf) {
		onChangeRemove(conf); // usuwanie z listy słuchających zmian

		// powiadamianie użytkowników o wyjściu
		sendTo(conf.getMembers(), new MemberChange(getLogin(), "exited", conf
				.getConferenceId()));

		// wywalenie z panelu konferencji
		confPanel.removeConference(conf);
	}

}